/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file accessibility_espeak_player.h
 * @brief 针对espeak tts引擎实现的无障碍播放器。由于espeak合成语音的逻辑与flite不同，因此需要单独实现。  
 * @brief Play函数提供给espeak回调函数SynthCallback使用，每次espeak_Synth合成之前需调用Interrupt()重置播放状态。
 * @brief 单次espeak_Synth合成的过程中，espeak会多次调用SynthCallback。
 */

#ifndef ACCESSIBILITY_ESPEAK_PLAYER_H
#define ACCESSIBILITY_ESPEAK_PLAYER_H

#include "singleton.h"
#include "audio_renderer.h" //AudioRenderer
#include <vector>
#include <queue>
#include <thread>  
#include <mutex>  
#include <condition_variable>

#define SINGLE_WRITE_BYTES 4096

namespace OHOS {
namespace Accessibility {

struct WavData
{
    uint8_t *data;
    size_t length; //bytes
};

const WavData END_WAV = {nullptr, -1};//合成结束标志，即单次合成的最后一个wavdata

class WavQueue
{
public:
    void Push(short *wav, int numsamples)
    {
        std::lock_guard<std::mutex> lock(mutex_);
        if(stopFlag_ == true) {
            stopFlag_ = false;
        }
        // wav格式转换
        int length = numsamples * sizeof(short);
        uint8_t *data = (uint8_t *)malloc(length);
        memcpy(data, wav, length);

        wavQueue_.push({data, length});
        cond_.notify_one();
    }

    void PushEnd(){
        std::lock_guard<std::mutex> lock(mutex_);
        wavQueue_.push(END_WAV);
        cond_.notify_one();
    }

    int Pop(uint8_t **wav)
    {
        std::unique_lock<std::mutex> lock(mutex_);
        cond_.wait(lock, [this] { return !wavQueue_.empty() || stopFlag_; });

        if (stopFlag_) {
            return 0;
        }
        WavData wavData = wavQueue_.front();
        wavQueue_.pop();
        *wav = wavData.data;
        return wavData.length;
    }

    //中断的时候调用stop，单次合成完毕不调用
    void Stop()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        stopFlag_ = true;
        cond_.notify_all();
    }

    void Clear()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        while (!wavQueue_.empty()) {
            WavData wavData = wavQueue_.front();
            wavQueue_.pop();
            free(wavData.data);
        }
    }

    bool IsEmpty()
    {
        std::lock_guard<std::mutex> lock(mutex_);
        return wavQueue_.empty();
    }

private:
    std::queue<WavData> wavQueue_;
    std::mutex mutex_;
    std::condition_variable cond_;
    bool stopFlag_ = false;//几乎没用，中断的时候设置为true，单次合成完毕不处理
};

class EspeakPlayer {
    DECLARE_SINGLETON(EspeakPlayer)
public:
    /**
     * @Description: 初始化EspeakPlayer
     */
    bool Init();
    /**
     * @Description: 释放EspeakPlayer  
     */
    bool Release();

    bool Start();
    bool Pause();
    bool Stop();
    bool Drain();
    bool Flush();
    bool SetParams(int32_t channels, int32_t sampleRate);
    /**
     * @Description: 对外写入音频数据接口
     * @param: short *wav
     * @Return: bool
     */
    void WriteToQueue(short *wav, int numsamples);
    /**
     * @Description: 中断播放，清空缓冲区
     * @Return: bool
     */
    void Interrupt();

    /**
     * @Description: 播放状态，实际上是判断队列是否为空
     * @Return: bool
     */
    bool IsPlaying();

private:

    /**
     * @Description: 将数据写入renderer渲染
     * @Return: bool
     */
    void WriteToRenderer(uint8_t *wav, int length);

    /**
     * @Description: 后台播放线程函数
     * @Return: void
     */
    void PlayBackThread();


    std::unique_ptr<AudioStandard::AudioRenderer> renderer_ = nullptr;
    //缓存audiorenderer支持的音频参数
    std::vector<AudioStandard::AudioSamplingRate> supportedSampleList_;
    std::vector<AudioStandard::AudioChannel> supportedChannelsList_;

    bool exitFlag_ = false; //是否退出playThread_
    bool interruptFlag_ = false; //是否中断播放
    std::thread playThread_;
    WavQueue wavQueue_;
};

} // namespace Accessibility
} // namespace OHOS

#endif // ACCESSIBILITY_ESPEAK_PLAYER_H